
// ===============================================================================================================
// -*- C++ -*-
//
// Log.hpp - Declaration of the Log and LogListener classes. Demonstrates the use of the Observer Design pattern.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __LOG_HPP__
#define __LOG_HPP__

#include <list>
#include <cstdio>

///
/// LogListener -- Simple log listener interface.
/// Objects that wish to listen to the log can implement this interface.
///
class LogListener {

public:

	/// Receive a message from the log. User must implement it own handling of the message.
	virtual void ReceiveMessage(const std::string & msg) = 0;

	virtual ~LogListener(void) { /**/ }
};

///
/// Log -- Singleton class with debug loggin utilities.
/// The log class is observable.
///
class Log {

public:

	/// Maximum string length the log can print, including the '\0'.
	enum { MAX_STRING_LEN = 2048 };

	/// Get the singleton instance.
	static Log& Instance(void);

	/// Open a new empty log for writting. Close previous.
	bool Open(const std::string & fileName);

	/// Check is a log file is currently open.
	bool IsOpen(void) const;

	/// Close the current log.
	void Close(void);

	/// Flush the current log.
	void Flush(void);

	/// Do the actual writting to the log file and also notify its listeners.
	void Write(const char * format, ...);

	/// Add listener to listeners list. Messages sent to the log are broadcasted to all registered listeners.
	/// This method validates the object pointer and do not allow duplicates to be inserted in the list. 
	void AddListener(LogListener * listener);

	/// Remove listener from the listeners list if this is in the list.
	void RemoveListener(LogListener * listener);

	/// Return the number of registered listeners.
	size_t NumberOfListeners(void) const;

public:

	// Output stream operators:

	Log& operator << (const std::string & text);
	Log& operator << (const char * text);

	Log& operator << (char ch);
	Log& operator << (const void * ptr);

	Log& operator << (short value);
	Log& operator << (unsigned short value);

	Log& operator << (int value);
	Log& operator << (unsigned int value);

	Log& operator << (float value);
	Log& operator << (double value);

protected:

	// Singleton, so construction is protected.

	Log(const Log &) { /* Disabled */ }
	Log& operator = (const Log &) { return (*this); }

	Log(void)
	: filePointer(0), listeners()
	{
	}

	~Log(void);

private:

	/// Broadcast a message to all registered listeners.
	void NotifyListeners(const std::string & msg) const;

	typedef std::list<LogListener *> ListenersList;
	ListenersList listeners; ///< The registered log listeners

	FILE * filePointer; ///< File stream. By default named as "Debug.log"
};

// ==== Debug Macros ====

#if defined (_DEBUG)

#define LOG_MSG(x)     { Log::Instance() << x << '\n'; }
#define LOG_ERROR(x)   { Log::Instance() << "Error: " << x << '\n'; }
#define LOG_WARNING(x) { Log::Instance() << "Warning: " << x << '\n'; }

#else

#define LOG_MSG(x)     /* Disabled */
#define LOG_ERROR(x)   /* Disabled */
#define LOG_WARNING(x) /* Disabled */

#endif // _DEBUG

#endif // __LOG_HPP__